#include "stdafx.h"
#include "OgreApplication.h"
 
#include <OgreException.h>
#include <OgreConfigFile.h>
#include <OgreCamera.h>
#include <OgreViewport.h>
#include <OgreSceneManager.h>
#include <OgreRenderWindow.h>
#include <OgreMeshManager.h>
#include <OgreEntity.h>
#include "Input.h"
#include "PlayerAvatar.h"
//#include "MainMenuState.h"
//#include "GameState.h"
#include "Model.h"
#include "MusicController.h"
#include "InputManager.h"
#include "PhysicsSystem.h"

//#include <Common/Base/KeyCode.cxx>
 
OgreApplication::OgreApplication(void)
	: m_root(0),
	 m_pluginsCfg(Ogre::StringUtil::BLANK),
	 m_resourcesCfg(Ogre::StringUtil::BLANK),
	 m_stateManager(0) {

}

OgreApplication::~OgreApplication(void) {
	delete m_root;
	delete m_stateManager;
	m_root = NULL;
	m_stateManager = NULL;
}

bool OgreApplication::configure(void) {
    // Show the configuration dialog and initialise the system
    // You can skip this and use root.restoreConfig() to load configuration
    // settings if you were sure there are valid ones saved in ogre.cfg
    if(m_root->showConfigDialog()) {
        // If returned true, user clicked OK so initialise
        // Here we choose to let the system create a default rendering window by passing 'true'
        m_window = m_root->initialise(true, "EbbEngine Render Window");
		StateManager::getInstance()->setWindow(m_window);
		InputManager::getInstance()->initialize(m_window);
        return true;
    } else {
        return false;
    }
}

bool OgreApplication::setup(void) {
	//Choose path for resources and plugin files depending on debug or release config
	#ifdef _DEBUG
		m_resourcesCfg = "resources_d.cfg";
		m_pluginsCfg = "plugins_d.cfg";
	#else
		m_resourcesCfg = "resources.cfg";
		m_pluginsCfg = "plugins.cfg";
	#endif

	//Create the Root object.    
    m_root = new Ogre::Root(m_pluginsCfg);
	StateManager::getInstance()->setRoot(m_root);

	// Define the resources that Ogre will use.
	// Load resource paths from config file
	Ogre::ConfigFile cf;
	cf.load(m_resourcesCfg);

	// Go through all sections & settings in the file
	Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();
 
	Ogre::String secName, typeName, archName;
	while (seci.hasMoreElements()) {
		secName = seci.peekNextKey();
		Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
		Ogre::ConfigFile::SettingsMultiMap::iterator i;
		for (i = settings->begin(); i != settings->end(); ++i) {
			typeName = i->first;
			archName = i->second;
			Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
				archName, typeName, secName);
		}
	}

	/*
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation("media/Materials", "FileSystem");
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation("media/Particles", "FileSystem");
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation("media/Textures", "FileSystem");*/

    //Choose and set up the RenderSystem (that is, DirectX, OpenGL, etc).
	// configure
	// Show the configuration dialog and initialise the system
	/*if(!(m_root->restoreConfig() || m_root->showConfigDialog())) {
		return false;
	}*/

	bool carryOn = configure();
    if (!carryOn) {
		return false;
	}

    //Create the RenderWindow (the window which Ogre resides in).
	
	// Set default mipmap level (note: some APIs ignore this)
	Ogre::TextureManager::getSingleton().setDefaultNumMipmaps(5);
	// initialise all resource groups
	Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();

    //Initialise the resources that you are going to use.
    //Create a scene using those resources.
	// Create the SceneManager, in this case a generic one
	//m_sceneMgr = m_root->createSceneManager("DefaultSceneManager");
	// Create the camera
	
	createScene();
	
	return true;
}

void OgreApplication::destroyScene(void) {

}

void OgreApplication::initPhysics() {
	PhysicsSystem::getInstance();
	//PhysicsSystem* PhysicsSystem = new PhysicsSystem(true);
	
	// TODO REMOVE CREATE ALL BOUNDING BOXES IN HERE
	// TODO REMOVE AND REPLACE WITH A GAME OBJECT SOMEWHERE
	//PhysicsSystem::getInstance()->addFixedSurface(hkVector4(0,0,0), hkVector4(50.0f,1.0f,50.0f));
	//PhysicsSystem::getInstance()->createPlane( 0.0f, 0.0f, 0.0f, 100.0f, 100.0f, 1.0f );
	//PhysicsSystem::getInstance()->addMovingBoxes(hkVector4(0.0f,-10.0f,0.0f), hkVector4(10.0f,10.0f,10.0f));
	//PhysicsSystem::getInstance()->addMovingBoxes(hkVector4(0.0f,150.0f,0.0f), hkVector4(10.0f,10.0f,10.0f));
	//PhysicsSystem::getInstance()->addMovingBoxes(hkVector4(0.0f,40.0f,0.0f), hkVector4(10.0f,10.0f,10.0f));
	
	// TODO REMOVE LATER ON, ADDING BOUNDING BOX TO THE PENGUINS
	//PhysicsSystem::getInstance()->addMovingBoxes(hkVector4((i/60),80,0), hkVector4(1.0f,1.0f,1.0f));

	/*
	//create watch object - we will simulate for 30 seconds of real time
	hkStopwatch stopWatch;
	stopWatch.start();
	hkReal lastTime = stopWatch.getElapsedSeconds();

	//initialize fixed time step - one step every 1/60 of a second
	hkReal timestep = 1.f / 60.f;
	//calculate number of steps for entire loop 
	//(30 seconds divided by single time step)
	int numSteps = int(30.f / timestep);

	//application loop, breaks after 15 real time seconds
	for ( int i = 0; i < numSteps; ++i ) {
		//step the simulation and VDB
		PhysicsSystem::getInstance()->stepSimulation(timestep);
		PhysicsSystem::getInstance()->stepVisualDebugger(timestep);

		//if (i%120==0) PhysicsSystem->addMovingBoxes(hkVector4((i/60),80,0), hkVector4(1.0f,1.0f,1.0f));
		//if (i%120==0) PhysicsSystem::getInstance()->addMovingBoxes(hkVector4((i/60),80,0), hkVector4(1.0f,1.0f,1.0f));

		//pause until the actual time has passed
		while (stopWatch.getElapsedSeconds() < lastTime + timestep);
		{	
			lastTime += timestep;
		}
	}*/	
}

bool OgreApplication::createScene(void) {
	m_stateManager = StateManager::getInstance();

	//TODO fult anrop av initalize
	//PhysicsSystem::getInstance();

	initPhysics();

	// Default state, app should start in menu
	
	//MainMenuState* mainMenuState = new MainMenuState();
	//mainMenuState->initalize(m_window);
	//m_stateManager->setState(mainMenuState);
	m_stateManager->startMenuState();
	
	
	// For debugging, app starts ingame rather than with menu
	/*
	GameState* gameState = new GameState();
	gameState->initalize(m_window);
	m_stateManager->setState(gameState);
	*/
	//m_stateManager->startGameState();
	return true;
}

bool OgreApplication::go(void) {
	if (!setup()) {
        return false;
	}

    //Start the render loop. 
	m_root->startRendering();

	destroyScene();
    return true;
}

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
	#define WIN32_LEAN_AND_MEAN
	#include "windows.h"
#endif
 
#ifdef __cplusplus
	extern "C" {
#endif
 
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
    INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
    int main(int argc, char *argv[])
#endif
    {
        // Create application object
        OgreApplication app;
 
        try {
            app.go();
        } catch( Ogre::Exception& e ) {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
            MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
            std::cerr << "An exception has occured: " << e.getFullDescription().c_str() << std::endl;
#endif
        }
 
        return 0;
    }
 
#ifdef __cplusplus
}
#endif